package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.dto.UserEcologyHatchRecordsDao;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.NftRegionBindingEditDTO;
import com.sc.nft.entity.dto.NftRegionBindingPageDTO;
import com.sc.nft.entity.dto.NftRegionBindingSaveDTO;
import com.sc.nft.entity.vo.NftRegionBindingPageVO;
import com.sc.nft.entity.vo.NftRegionBindingUserVO;
import com.sc.nft.enums.RegionLevelEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.AdministrativeAreaService;
import com.sc.nft.service.DigitalCollectionService;
import com.sc.nft.service.NftRegionBindingService;
import com.sc.nft.util.LocalDateTimeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * nft版权部分绑定(NftRegionBinding)表服务实现类
 *
 * @author 王伟成
 * @since 2023-10-11 16:47:36
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class NftRegionBindingServiceImpl implements NftRegionBindingService {

    private final NftRegionBindingDao nftRegionBindingDao;
    private final IdcardInfoDao idcardInfoDao;
    private final SysRegionDao sysRegionDao;
    private final UserEcologyHatchRecordsDao userEcologyHatchRecordsDao;
    private final CopyrightAuctionConfigDao copyrightAuctionConfigDao;
    private final DigitalCollectionService digitalCollectionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateActivation() {
        List<NftRegionBinding> nftRegionBindings = nftRegionBindingDao.list();
        for (NftRegionBinding nftRegionBinding : nftRegionBindings) {
            Long regionId = null;
            RegionLevelEnum regionLevel = nftRegionBinding.getRegionLevel();
            if (regionLevel == RegionLevelEnum.PROVINCE) {
                regionId = nftRegionBinding.getProvinceId();
            } else if (regionLevel == RegionLevelEnum.CITY) {
                regionId = nftRegionBinding.getCityId();
            } else if (regionLevel == RegionLevelEnum.REGION) {
                regionId = nftRegionBinding.getRegionId();
            }
            if (Objects.isNull(regionId)) {
                return;
            }

            SysRegion sysRegion = sysRegionDao.administrationById(regionId);
            if (Objects.isNull(sysRegion)) {
                continue;
            }

            String idCard;
            if (regionLevel == RegionLevelEnum.PROVINCE) {
                idCard = sysRegion.getRegionCode().substring(0, 2);
            } else if (regionLevel == RegionLevelEnum.CITY) {
                idCard = sysRegion.getRegionCode().substring(0, 4);
            } else {
                idCard = sysRegion.getRegionCode().substring(0, 6);
            }
            List<IdcardInfo> idCardInfos = idcardInfoDao.listIdCardByRegion(idCard);
            if (CollectionUtils.isEmpty(idCardInfos)) {
                continue;
            }
            List<Long> userIds = idCardInfos.stream().map(IdcardInfo::getUserId).collect(Collectors.toList());
            List<UserEcologyHatchRecords> userEcologyHatchRecords = userEcologyHatchRecordsDao.listByUserId(userIds);
            BigDecimal reduce = userEcologyHatchRecords.stream()
                    .map(UserEcologyHatchRecords::getRealEcologyPoints)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            nftRegionBinding.setActivation(reduce);
            LambdaUpdateWrapper<NftRegionBinding> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(NftRegionBinding::getId, nftRegionBinding.getId());
            updateWrapper.set(NftRegionBinding::getActivation, reduce);
            nftRegionBindingDao.update(updateWrapper);
        }
    }

    @Override
    public BigDecimal getMapProsperity(Long nftId) {
        if (Objects.isNull(nftId)) {
            return BigDecimal.ZERO;
        }
        List<NftRegionBinding> nftRegionBindings = nftRegionBindingDao.selectByCollectionId(nftId);
        if (CollectionUtils.isEmpty(nftRegionBindings)) {
            return BigDecimal.ZERO;
        }
        return nftRegionBindings.get(0).getActivation() == null ? BigDecimal.ZERO : nftRegionBindings.get(0).getActivation();
    }


    @Override
    public List<NftRegionBindingUserVO> listBindUserId() {
        return nftRegionBindingDao.listBindUserId();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNftEffectiveTime(Long nftId) {
        if (Objects.isNull(nftId)) {
            throw new GlobalRunTimeException("nftId和不能为空");
        }
        CopyrightAuctionConfig auctionConfig = copyrightAuctionConfigDao.getNewOne();
        if (Objects.isNull(auctionConfig)) {
            throw new GlobalRunTimeException("nftId和不能为空");
        }

        List<NftRegionBinding> nftRegionBindings = nftRegionBindingDao.selectByCollectionId(nftId);
        for (NftRegionBinding nftRegionBinding : nftRegionBindings) {
            LocalDateTime now = LocalDateTime.now();
            if (RegionLevelEnum.PROVINCE == nftRegionBinding.getRegionLevel()) {
                now = LocalDateTime.now().plusDays(auctionConfig.getProvinceInterestsTime());
            } else if (RegionLevelEnum.CITY == nftRegionBinding.getRegionLevel()) {
                now = LocalDateTime.now().plusDays(auctionConfig.getCityInterestsTime());
            } else if (RegionLevelEnum.REGION == nftRegionBinding.getRegionLevel()) {
                now = LocalDateTime.now().plusDays(auctionConfig.getInterestsTime());
            } else {
                continue;
            }
            Date date = LocalDateTimeUtil.localDateTimeToDate(now);
            nftRegionBinding.setEffectiveTime(date);
            LambdaUpdateWrapper<NftRegionBinding> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(NftRegionBinding::getId, nftRegionBinding.getId());
            if (!nftRegionBindingDao.update(nftRegionBinding, updateWrapper)) {
                throw new GlobalRunTimeException("更新nft有效期失败!");
            }
        }

    }

    @Override
    public Date getNftEffectiveTime(Long nftId) {
        if (Objects.isNull(nftId)) {
            return null;
        }
        List<NftRegionBinding> nftRegionBindings = nftRegionBindingDao.selectByCollectionId(nftId);
        if (CollectionUtils.isEmpty(nftRegionBindings)) {
            return null;
        }
        return nftRegionBindings.get(0).getEffectiveTime();
    }


    /**
     * 获取nft是否有绑定地图
     *
     * @param nftId nftId
     * @return Date 权益时间
     */
    @Override
    public Boolean getNftBinding(Long nftId) {
        List<NftRegionBinding> nftRegionBindings = nftRegionBindingDao.selectByCollectionId(nftId);
        if (CollectionUtils.isEmpty(nftRegionBindings)) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @Override
    public void save(NftRegionBindingSaveDTO nftRegionBindingSave) {
        List<DigitalCollection> list = digitalCollectionService.getCollectionListById(Lists.newArrayList(nftRegionBindingSave.getCollectionId()));
        if (CollectionUtils.isEmpty(list)) {
            throw new GlobalRunTimeException(nftRegionBindingSave.getCollectionId() + "藏品不存在");
        }
        //检查是否绑定省
        List<NftRegionBinding> nftRegionBindings = nftRegionBindingDao.selectProvinceIdAndCityIdAndAreaIdAndCollectionId(nftRegionBindingSave.getCollectionId(), null, null, null, null);
        if (CollUtil.isNotEmpty(nftRegionBindings)) {
            throw new GlobalRunTimeException(StrUtil.format("该藏品已绑定到:{}-{}-{}", nftRegionBindings.get(0).getProvinceName(), nftRegionBindings.get(0).getCityName(), nftRegionBindings.get(0).getRegionName()));
        }

        NftRegionBinding nftRegionBinding = getNftRegionBinding(nftRegionBindingSave);
        nftRegionBindingDao.save(nftRegionBinding);
    }

    @Override
    public void edit(NftRegionBindingEditDTO edit) {
        Long collectionId = edit.getCollectionId();
        List<NftRegionBinding> list = nftRegionBindingDao.selectByCollectionId(collectionId);
        if (CollUtil.isEmpty(list)) {
            throw new GlobalRunTimeException("藏品不存在");
        }
        NftRegionBinding nftRegionBinding = list.get(0);
        //标记等级
        RegionLevelEnum regionLevelEnum = RegionLevelEnum.PROVINCE;
        if (Objects.nonNull(edit.getCityId())) {
            regionLevelEnum = RegionLevelEnum.CITY;
        }
        if (Objects.nonNull(edit.getRegionId())) {
            regionLevelEnum = RegionLevelEnum.REGION;
        }
        nftRegionBinding.setRegionLevel(regionLevelEnum);
        nftRegionBinding.setProvinceId(edit.getProvinceId());
        nftRegionBinding.setProvinceName(edit.getProvinceName());
        nftRegionBinding.setCityId(edit.getCityId());
        nftRegionBinding.setCityName(edit.getCityName());
        nftRegionBinding.setRegionId(edit.getRegionId());
        nftRegionBinding.setRegionName(edit.getRegionName());
        nftRegionBindingDao.updateById(nftRegionBinding);

    }

    @Override
    public void removeById(Long id) {
        nftRegionBindingDao.removeById(id);
    }

    @Override
    public Page<NftRegionBindingPageVO> page(NftRegionBindingPageDTO nftRegionBindingPageDTO) {
        return nftRegionBindingDao.nftRegionBindingPage(nftRegionBindingPageDTO.toMp(), nftRegionBindingPageDTO);
    }


    private static NftRegionBinding getNftRegionBinding(NftRegionBindingSaveDTO regionBindingSave) {
        //标记等级
        RegionLevelEnum regionLevelEnum = RegionLevelEnum.PROVINCE;
        if (Objects.nonNull(regionBindingSave.getCityId())) {
            regionLevelEnum = RegionLevelEnum.CITY;
        }
        if (Objects.nonNull(regionBindingSave.getRegionId())) {
            regionLevelEnum = RegionLevelEnum.REGION;
        }
        NftRegionBinding nftRegionBinding = new NftRegionBinding();
        nftRegionBinding.setRegionLevel(regionLevelEnum);
        nftRegionBinding.setCollectionId(regionBindingSave.getCollectionId());
        nftRegionBinding.setProvinceId(regionBindingSave.getProvinceId());
        nftRegionBinding.setCityId(regionBindingSave.getCityId());
        nftRegionBinding.setRegionId(regionBindingSave.getRegionId());
        nftRegionBinding.setProvinceName(regionBindingSave.getProvinceName());
        nftRegionBinding.setCityName(regionBindingSave.getCityName());
        nftRegionBinding.setRegionName(regionBindingSave.getRegionName());
        return nftRegionBinding;
    }

}
